package netective.gui.charts;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Calendar;

import netective.api.analyzer.PredictionType;
import netective.dao.ClassType;
import netective.dao.VirtualResultSet;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.SeriesDataset;
import org.jfree.data.time.Day;
import org.jfree.data.time.Hour;
import org.jfree.data.time.Minute;
import org.jfree.data.time.Month;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.time.Year;
import org.jfree.data.xy.XYDataset;

@SuppressWarnings("serial")
public class TimeSeriesChart extends ChartPanel {

	private ChartGrain g;
	private PredictionType prediction = PredictionType.None;

	protected TimeSeriesChart(JFreeChart timeSeriesChart, String chartTitle,
			ResultSet[] data, String[] legend, ChartGrain g, PredictionType p) {
		this(null, chartTitle, data, legend, "Count of packets", g, p);
	}

	protected TimeSeriesChart(JFreeChart timeSeriesChart, String chartTitle,
			ResultSet[] data, String[] legend, String axis, ChartGrain g,
			PredictionType p) {
		super(timeSeriesChart);
		this.g = g;
		this.prediction = p;
		SetChart(chartTitle, data, legend, axis);

	}

	public void SetChart(String chartTitle, ResultSet[] data, String[] legend,
			String axis) {
		SeriesDataset dataset = createDataset(data, legend);

		JFreeChart chart = createChart(dataset, chartTitle, axis);
		this.setChart(chart);
		this.setPreferredSize(new java.awt.Dimension(500, 270));
	}

	private TimeSeriesCollection createDataset(ResultSet[] resultSet,
			String[] legend) {
		TimeSeriesCollection dataset = new TimeSeriesCollection();

		for (int i = 0; i < resultSet.length; i++) {
			TimeSeries t = createTimeSeries(resultSet[i], legend[i]);
			if (t != null)
				dataset.addSeries(t);
		}

		// do generowania wykresów predykcji
		for (int i = 0; i < resultSet.length; i++) {
			switch (prediction) {
			case Cusum:
				int valueColumn = getColumnsCountInResultSet();
				VirtualResultSet<ResultSet> rsTmp = new VirtualResultSet<ResultSet>(resultSet[i],
						getRowsCountInResultSet(resultSet[i]),
						getColumnsCountInResultSet(), ClassType.Double);
				if (rsTmp != null) {
					double avg = calculateAvg(rsTmp);
					System.out.println("Average value is: " + avg);
					double cusum = 0;
					rsTmp.beforeFirst();
					while (rsTmp.next()) {
						double value = rsTmp.getDouble(valueColumn);
						rsTmp.setDouble(valueColumn, cusum);
						cusum = cusum + (value - avg);
					}
					rsTmp.beforeFirst();
					TimeSeries t = createTimeSeries(rsTmp, legend[i] + " CUSUM");
					if (t != null)
						dataset.addSeries(t);
				}
				break;
			}
		}

		return dataset;
	}

	@SuppressWarnings("deprecation")
	private TimeSeries createTimeSeries(ResultSet resultSet, String legend) {

		TimeSeries result = null;
		if (legend == null)
			return null;

		try {
			switch (g) {
			case Minute: {
				result = new TimeSeries(legend, Minute.class);
				if (resultSet != null) {
					while (resultSet.next()) {
						result.add(
								new Minute(resultSet.getInt(1), resultSet
										.getInt(2), resultSet.getInt(3),
										resultSet.getInt(4), resultSet
												.getInt(5)), resultSet
										.getInt(6));
					}
					if (result.isEmpty()) {
						result.add(
								new Minute(Calendar.getInstance().get(
										Calendar.MINUTE) - 1, Calendar
										.getInstance()
										.get(Calendar.HOUR_OF_DAY), Calendar
										.getInstance().get(
												Calendar.DAY_OF_MONTH),
										Calendar.getInstance().get(
												Calendar.MONTH) + 1, Calendar
												.getInstance().get(
														Calendar.YEAR)), 0);

					}

				}
				break;
			}
			case Hour: {
				result = new TimeSeries(legend, Hour.class);
				if (resultSet != null) {
					while (resultSet.next()) {
						result.add(
								new Hour(resultSet.getInt(1), resultSet
										.getInt(2), resultSet.getInt(3),
										resultSet.getInt(4)), resultSet
										.getInt(5));
					}
					if (result.isEmpty()) {
						result.add(
								new Hour(Calendar.getInstance().get(
										Calendar.HOUR_OF_DAY), Calendar
										.getInstance().get(
												Calendar.DAY_OF_MONTH),
										Calendar.getInstance().get(
												Calendar.MONTH) + 1, Calendar
												.getInstance().get(
														Calendar.YEAR)), 0);

					}

				}
				break;
			}
			case Day: {
				result = new TimeSeries(legend, Day.class);
				if (resultSet != null) {
					while (resultSet.next()) {
						result.add(
								new Day(resultSet.getInt(1), resultSet
										.getInt(2), resultSet.getInt(3)),
								resultSet.getInt(4));
					}
					if (result.isEmpty()) {
						result.add(
								new Day(Calendar.getInstance().get(
										Calendar.DAY_OF_MONTH), Calendar
										.getInstance().get(Calendar.MONTH) + 1,
										Calendar.getInstance().get(
												Calendar.YEAR)), 0);

					}

				}
				break;
			}
			case Month: {
				result = new TimeSeries(legend, Month.class);
				if (resultSet != null) {
					while (resultSet.next()) {
						result.add(
								new Month(resultSet.getInt(1), resultSet
										.getInt(2)), resultSet.getInt(3));
					}
					if (result.isEmpty()) {
						result.add(
								new Month(Calendar.getInstance().get(
										Calendar.MONTH) + 1, Calendar
										.getInstance().get(Calendar.YEAR)), 0);

					}

				}
				break;
			}
			default: {
				result = new TimeSeries(legend, Year.class);
				if (resultSet != null) {
					while (resultSet.next()) {
						result.add(new Year(resultSet.getInt(1)),
								resultSet.getInt(2));
					}
					if (result.isEmpty()) {
						result.add(
								new Year(Calendar.getInstance().get(
										Calendar.YEAR)), 0);

					}

				}
				break;
			}

			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return result;
	}

	private JFreeChart createChart(SeriesDataset dataset, String title,
			String axis) {

		JFreeChart chart = ChartFactory.createTimeSeriesChart(title, "Time ("
				+ g + "s)", axis, (XYDataset) dataset, true, true, false);

		return chart;
	}

	private double calculateAvg(ResultSet rs) {
		double sum = 0;
		double count = 0;
		int valueColumn = getColumnsCountInResultSet();
		try {
			rs.beforeFirst();
			while (rs.next()) {
				sum += rs.getDouble(valueColumn);
				count++;
			}
			return sum / count;
		} catch (SQLException e) {
		}

		return 0;
	}

	private int getColumnsCountInResultSet() {
		switch (g) {
		case Minute:
			return 6;
		case Hour:
			return 5;
		case Day:
			return 4;
		case Month:
			return 3;
		default:
			return 2;
		}
	}

	private int getRowsCountInResultSet(ResultSet rs) {
		int rows = 0;
		try {
			rs.beforeFirst();
			while (rs.next()) {
				rows++;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}

		return rows;

	}

	public void setPrediction(PredictionType prediction) {
		this.prediction = prediction;
	}

}
